//
//  EC2.m
//  cTypica
//
//  Created by David Kavanagh on 10/14/08.
//  Copyright 2008 directThought. All rights reserved.
//

#import "EC2.h"
#import	"ImageDescriptionDelegate.h"
#import	"ReservationDescriptionDelegate.h"
#import "VolumeInfoDelegate.h"
#import "AttachmentInfoDelegate.h"
#import "SnapshotInfoDelegate.h"
#import "CreateSnapshotDelegate.h"
#import "SecurityGroupDelegate.h"
#import "AddressDelegate.h"
#import "AllocateDelegate.h"
#import "BooleanDelegate.h"
#import "KeypairDelegate.h"
#import "TerminateDelegate.h"
#import "LaunchDelegate.h"
#import "CreateVolumeDelegate.h"
#import "ZonesDelegate.h"
#import "RegionDelegate.h"
#import "ConsoleDelegate.h"
#import <Foundation/NSXMLParser.h>
#import "LGXMLParser.h"
#import "Base64Transcoder.h"

@implementation EC2

- (id)initWithAccessId:(NSString *)aId secretKey:(NSString *)sKey {
	self = [super initWithAccessId:accessId secretKey:secretKey hostName:@"ec2.amazonaws.com"];
	version = @"2008-12-01";
	return self;
}

- (id)initWithAccessId:(NSString *)aId secretKey:(NSString *)sKey hostName:(NSString *)hName {
	self = [super initWithAccessId:aId secretKey:sKey hostName:hName];
	version = @"2008-12-01";
	return self;
}

- (void)describeImages:(BOOL)all receiver:(id<ImageDescriptionProtocol>)receiver {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (!all) {
		[params setValue:@"self" forKey:@"Owner.1"];
	}
	ImageDescriptionDelegate *delegate = [ImageDescriptionDelegate delegateWithReceiver:receiver];
	[self makeRequest:@"DescribeImages" parameters:params delegate:delegate];
	//[params release];
	//[delegate release];
}

- (void)describeInstances:(NSArray *)instanceIds receiver:(id<ReservationDescriptionProtocol>)receiver {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (instanceIds != nil) {
		NSString *iId;
		NSEnumerator *iIds = [instanceIds objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"InstanceId.%d", idx]];
		}
	}
	ReservationDescriptionDelegate *delegate = [ReservationDescriptionDelegate delegateWithReceiver:receiver];
	[self makeRequest:@"DescribeInstances" parameters:params delegate:delegate];
	[params release];
	[delegate release];
}

- (NSArray *)describeVolumes:(NSArray *)volumeIds {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (volumeIds != nil) {
		NSString *iId;
		NSEnumerator *iIds = [volumeIds objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"VolumeId.%d", idx]];
		}
	}
	VolumeInfoDelegate *delegate = [VolumeInfoDelegate delegate];
	[self makeRequest:@"DescribeVolumes" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate volumeInfo];
	[delegate release];
	return ret;
}

- (NSArray *)describeSnapshots:(NSArray *)snapshotIds {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (snapshotIds != nil) {
		NSString *iId;
		NSEnumerator *iIds = [snapshotIds objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"SnapshotId.%d", idx]];
		}
	}
	SnapshotInfoDelegate *delegate = [SnapshotInfoDelegate delegate];
	[self makeRequest:@"DescribeSnapshots" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate snapshotInfo];
	[delegate release];
	return ret;
}

- (NSArray *)describeSecurityGroups:(NSArray *)groupNames {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (groupNames != nil) {
		NSString *iId;
		NSEnumerator *iIds = [groupNames objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"GroupName.%d", idx]];
		}
	}
	SecurityGroupDelegate *delegate = [SecurityGroupDelegate delegate];
	[self makeRequest:@"DescribeSecurityGroups" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate groups];
	[delegate release];
	return ret;
}

- (NSArray *)describeAddresses:(NSArray *)addresses {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (addresses != nil) {
		NSString *iId;
		NSEnumerator *iIds = [addresses objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"PublicIp.%d", idx]];
		}
	}
	AddressDelegate *delegate = [AddressDelegate delegate];
	[self makeRequest:@"DescribeAddresses" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate addresses];
	[delegate release];
	return ret;
}

- (NSArray *)describeKeypairs:(NSArray *)keys {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (keys != nil) {
		NSString *iId;
		NSEnumerator *iIds = [keys objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"KeyName.%d", idx]];
		}
	}
	KeypairDelegate *delegate = [KeypairDelegate delegate];
	[self makeRequest:@"DescribeKeyPairs" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate keypairs];
	[delegate release];
	return ret;
}

- (void)runInstances:(LaunchConfiguration *)config receiver:(id<ReservationDescriptionProtocol>)receiver {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:config.imageId forKey:@"ImageId"];
	[params setValue:[NSString stringWithFormat:@"%d", config.minCount] forKey:@"MinCount"];
	[params setValue:[NSString stringWithFormat:@"%d", config.maxCount] forKey:@"MaxCount"];
	if (config.keyName != nil) {
		[params setValue:config.keyName forKey:@"KeyName"];
	}
	if (config.securityGroups != nil) {
		NSString *iId;
		NSEnumerator *iIds = [config.securityGroups objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"SecurityGroup.%d", idx]];
		}
	}
	if (config.availabilityZone != nil) {
		[params setValue:config.availabilityZone forKey:@"Placement.AvailabilityZone"];
	}
	if (config.userData != nil) {
		int dataLen = [config.userData length];
		unsigned char dataBytes[dataLen];
		[config.userData getBytes: &dataBytes];
		size_t encodedLen = EstimateBas64EncodedDataSize(dataLen);
		char encodedData[encodedLen];
		Base64EncodeData(dataBytes, dataLen, encodedData, &encodedLen);
		[params setValue:[[NSString alloc] initWithData:[NSData dataWithBytes:encodedData length: encodedLen] encoding:NSUTF8StringEncoding] forKey:@"UserData"];
	}
	if (config.instanceType != nil) {
		[params setValue:config.instanceType forKey:@"InstanceType"];
	}
	if (config.kernelId != nil) {
		[params setValue:config.kernelId forKey:@"KernelId"];
	}
	if (config.ramdiskId != nil) {
		[params setValue:config.ramdiskId forKey:@"RamdiskId"];
	}
	if (config.blockDeviceMapping != nil) {
		BlockDeviceMapping *mapping;
		NSEnumerator *mappings = [config.blockDeviceMapping objectEnumerator];
		int idx = 0;
		while (mapping = [mappings nextObject]) {
			[params setValue:mapping.virtualName forKey:[NSString stringWithFormat:@"BlockDeviceMapping.%d.VirtualName", idx]];
			[params setValue:mapping.deviceName forKey:[NSString stringWithFormat:@"BlockDeviceMapping.%d.DeviceName", idx]];
		}
	}
	LaunchDelegate *delegate = [LaunchDelegate delegateWithReceiver:receiver];
	[self makeRequest:@"RunInstances" parameters:params delegate:delegate];
	[params release];
	[delegate release];
}

- (NSArray *)terminateInstances:(NSArray *)instanceIds {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (instanceIds != nil) {
		NSString *iId;
		NSEnumerator *iIds = [instanceIds objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"InstanceId.%d", idx]];
		}
	}
	TerminateDelegate *delegate = [TerminateDelegate delegate];
	[self makeRequest:@"TerminateInstances" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate instanceInfo];
	[delegate release];
	return ret;
}

- (NSArray *)rebootInstances:(NSArray *)instanceIds {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (instanceIds != nil) {
		NSString *iId;
		NSEnumerator *iIds = [instanceIds objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"InstanceId.%d", idx]];
		}
	}
	TerminateDelegate *delegate = [TerminateDelegate delegate];
	[self makeRequest:@"RebootInstances" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate instanceInfo];
	[delegate release];
	return ret;
}

- (ConsoleInfo *)getConsoleOutput:(NSString *)instanceId {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:instanceId forKey:@"InstanceId"];
	ConsoleDelegate *delegate = [ConsoleDelegate delegate];
	[self makeRequest:@"GetConsoleOutput" parameters:params delegate:delegate];
	[params release];
	ConsoleInfo *ret = [delegate output];
	[delegate release];
	return ret;
}

- (NSString *)allocateAddress {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	AllocateDelegate *delegate = [AllocateDelegate delegate];
	[self makeRequest:@"AllocateAddress" parameters:params delegate:delegate];
	[params release];
	NSString *ret = [delegate address];
	[delegate release];
	return ret;
}

- (void)associateAddress:(NSString *)address instanceId:(NSString *)instanceId {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:address forKey:@"PublicIp"];
	[params setValue:instanceId forKey:@"InstanceId"];
	BooleanDelegate *delegate = [BooleanDelegate delegate];
	[self makeRequest:@"AssociateAddress" parameters:params delegate:delegate];
	[params release];
	if (![delegate success]) {
		// call the error delegate
	}
	[delegate release];
}

- (void)disassociateAddress:(NSString *)instanceId {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:instanceId forKey:@"InstanceId"];
	BooleanDelegate *delegate = [BooleanDelegate delegate];
	[self makeRequest:@"DisassociateAddress" parameters:params delegate:delegate];
	[params release];
	if (![delegate success]) {
		// call the error delegate
	}
	[delegate release];
}

- (void)releaseAddress:(NSString *)address {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:address forKey:@"PublicIp"];
	BooleanDelegate *delegate = [BooleanDelegate delegate];
	[self makeRequest:@"ReleaseAddress" parameters:params delegate:delegate];
	[params release];
	if (![delegate success]) {
		// call the error delegate
	}
	[delegate release];
}

- (VolumeInfo *)createVolume:(NSString *)size snapshotId:(NSString *)snapId zoneName:(NSString *)zone {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (size != nil && ![size isEqualToString:@""]) {
		[params setValue:size forKey:@"Size"];
	}
	if (snapId != nil && ![snapId isEqualToString:@""]) {
		[params setValue:snapId forKey:@"SnapshotId"];
	}
	[params setValue:zone forKey:@"AvailabilityZone"];
	CreateVolumeDelegate *delegate = [CreateVolumeDelegate delegate];
	[self makeRequest:@"CreateVolume" parameters:params delegate:delegate];
	[params release];
	VolumeInfo *ret = [delegate volumeInfo];
	[delegate release];
	return ret;
}

- (void)deleteVolume:(NSString *)volumeId {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:volumeId forKey:@"VolumeId"];
	BooleanDelegate *delegate = [BooleanDelegate delegate];
	[self makeRequest:@"DeleteVolume" parameters:params delegate:delegate];
	[params release];
	if (![delegate success]) {
		// call the error delegate
	}
	[delegate release];
}

- (AttachmentInfo *)attachVolume:(NSString *)volumeId instanceId:(NSString *)instanceId device:(NSString *)device {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:volumeId forKey:@"VolumeId"];
	[params setValue:instanceId forKey:@"InstanceId"];
	[params setValue:device forKey:@"Device"];
	AttachmentInfoDelegate *delegate = [AttachmentInfoDelegate delegate];
	[self makeRequest:@"AttachVolume" parameters:params delegate:delegate];
	[params release];
	AttachmentInfo *ret = [delegate attachmentInfo];
	[delegate release];
	return ret;
}

- (AttachmentInfo *)detachVolume:(NSString *)volumeId instanceId:(NSString *)instanceId device:(NSString *)device force:(Boolean)force {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:volumeId forKey:@"VolumeId"];
	[params setValue:instanceId forKey:@"InstanceId"];
	[params setValue:device forKey:@"Device"];
	AttachmentInfoDelegate *delegate = [AttachmentInfoDelegate delegate];
	[self makeRequest:@"DetachVolume" parameters:params delegate:delegate];
	[params release];
	AttachmentInfo *ret = [delegate attachmentInfo];
	[delegate release];
	return ret;
}

- (SnapshotInfo *)createSnapshot:(NSString *)volumeId; {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:volumeId forKey:@"VolumeId"];
	CreateSnapshotDelegate *delegate = [CreateSnapshotDelegate delegate];
	[self makeRequest:@"CreateSnapshot" parameters:params delegate:delegate];
	[params release];
	SnapshotInfo *ret = [delegate snapshotInfo];
	[delegate release];
	return ret;
}

- (void)deleteSnapshot:(NSString *)snapshotId {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	[params setValue:snapshotId forKey:@"SnapshotId"];
	BooleanDelegate *delegate = [BooleanDelegate delegate];
	[self makeRequest:@"DeleteSnapshot" parameters:params delegate:delegate];
	[params release];
	if (![delegate success]) {
		// call the error delegate
	}
	[delegate release];
}

- (NSArray *)describeAvailabilityZones:(NSArray *)zones {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (zones != nil) {
		NSString *iId;
		NSEnumerator *iIds = [zones objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"ZoneName.%d", idx]];
		}
	}
	ZonesDelegate *delegate = [ZonesDelegate delegate];
	[self makeRequest:@"DescribeAvailabilityZones" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate zones];
	[delegate release];
	return ret;
}

- (NSArray *)describeRegions:(NSArray *)regions {
	NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
	if (regions != nil) {
		NSString *iId;
		NSEnumerator *iIds = [regions objectEnumerator];
		int idx = 0;
		while (iId = [iIds nextObject]) {
			[params setValue:iId forKey:[NSString stringWithFormat:@"Region.%d", idx]];
		}
	}
	RegionDelegate *delegate = [RegionDelegate delegate];
	[self makeRequest:@"DescribeRegions" parameters:params delegate:delegate];
	[params release];
	NSMutableArray *ret = [delegate regions];
	[delegate release];
	return ret;
}

@end
